package v1beta1

/*
Copyright 2021-2025 The k8gb Contributors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic
*/

import (
	netv1 "k8s.io/api/networking/v1"
)

// IngressSpec overrides https://github.com/kubernetes/api/blob/master/networking/v1/types.go
// IngressSpec is upstream Ingress to be included in Gslb specification and extended with Gslb specific requirements.
type IngressSpec struct {
	// IngressClassName is the name of the IngressClass cluster resource. The
	// associated IngressClass defines which controller will implement the
	// resource. This replaces the deprecated `kubernetes.io/ingress.class`
	// annotation. For backwards compatibility, when that annotation is set, it
	// must be given precedence over this field. The controller may emit a
	// warning if the field and annotation have different values.
	// Implementations of this API should ignore Ingresses without a class
	// specified. An IngressClass resource may be marked as default, which can
	// be used to set a default value for this field. For more information,
	// refer to the IngressClass documentation.
	// +optional
	IngressClassName *string `json:"ingressClassName,omitempty" protobuf:"bytes,4,opt,name=ingressClassName"`

	// A default backend capable of servicing requests that don't match any
	// rule. At least one of 'backend' or 'rules' must be specified. This field
	// is optional to allow the loadbalancer controller or defaulting logic to
	// specify a global default.
	// +optional
	DefaultBackend *netv1.IngressBackend `json:"backend,omitempty" protobuf:"bytes,1,opt,name=defaultBackend"`

	// TLS configuration. Currently the Ingress only supports a single TLS
	// port, 443. If multiple members of this list specify different hosts, they
	// will be multiplexed on the same port according to the hostname specified
	// through the SNI TLS extension, if the ingress controller fulfilling the
	// ingress supports SNI.
	// +optional
	TLS []netv1.IngressTLS `json:"tls,omitempty" protobuf:"bytes,2,rep,name=tls"`

	// A list of host rules used to configure the Ingress. If unspecified, or
	// no rule matches, all traffic is sent to the default backend.
	// +optional
	Rules []IngressRule `json:"rules,omitempty" protobuf:"bytes,3,rep,name=rules"`
	// TODO: Add the ability to specify load-balancer IP through claims
}

// IngressRule represents the rules mapping the paths under a specified host to
// the related backend services. Incoming requests are first evaluated for a host
// match, then routed to the backend associated with the matching IngressRuleValue.
type IngressRule struct {
	// Host is the fully qualified domain name of a network host, as defined by RFC 3986.
	// Note the following deviations from the "host" part of the
	// URI as defined in RFC 3986:
	// 1. IPs are not allowed. Currently an IngressRuleValue can only apply to
	//    the IP in the Spec of the parent Ingress.
	// 2. The `:` delimiter is not respected because ports are not allowed.
	//	  Currently the port of an Ingress is implicitly :80 for http and
	//	  :443 for https.
	// Both these may change in the future.
	// Incoming requests are matched against the host before the
	// IngressRuleValue. If the host is unspecified, the Ingress routes all
	// traffic based on the specified IngressRuleValue.
	//
	// Host can be "precise" which is a domain name without the terminating dot of
	// a network host (e.g. "foo.bar.com") or "wildcard", which is a domain name
	// prefixed with a single wildcard label (e.g. "*.foo.com").
	// The wildcard character '*' must appear by itself as the first DNS label and
	// matches only a single label. You cannot have a wildcard label by itself (e.g. Host == "*").
	// Requests will be matched against the Host field in the following way:
	// 1. If Host is precise, the request matches this rule if the http host header is equal to Host.
	// 2. If Host is a wildcard, then the request matches this rule if the http host header
	// is to equal to the suffix (removing the first label) of the wildcard rule.
	// +optional
	Host string `json:"host,omitempty" protobuf:"bytes,1,opt,name=host"`
	// IngressRuleValue represents a rule to route requests for this IngressRule.
	// If unspecified, the rule defaults to a http catch-all. Whether that sends
	// just traffic matching the host to the default backend or all traffic to the
	// default backend, is left to the controller fulfilling the Ingress. Http is
	// currently the only supported IngressRuleValue.
	// +optional
	IngressRuleValue `json:",inline,omitempty" protobuf:"bytes,2,opt,name=ingressRuleValue"`
}

// IngressRuleValue represents a rule to apply against incoming requests. If the
// rule is satisfied, the request is routed to the specified backend. Currently
// mixing different types of rules in a single Ingress is disallowed, so exactly
// one of the following must be set.
type IngressRuleValue struct {
	//TODO:
	// 1. Consider renaming this resource and the associated rules so they
	// aren't tied to Ingress. They can be used to route intra-cluster traffic.
	// 2. Consider adding fields for ingress-type specific global options
	// usable by a loadbalancer, like http keep-alive.

	// HTTPIngressRuleValue is a list of http selectors
	// pointing to backends. In the example: http://<host>/<path>?<searchpart>
	// -> backend where where parts of the url correspond to
	// RFC 3986, this resource will be used to match against
	// everything after the last '/' and before the first '?'
	// or '#'.
	HTTP *netv1.HTTPIngressRuleValue `json:"http" protobuf:"bytes,1,opt,name=http"`
}

// DeepCopyInto copying the receiver, writing into out. in must be non-nil.
func (in *IngressSpec) DeepCopyInto(out *IngressSpec) {
	*out = *in
	if in.IngressClassName != nil {
		in, out := &in.IngressClassName, &out.IngressClassName
		*out = new(string)
		**out = **in
	}
	if in.DefaultBackend != nil {
		in, out := &in.DefaultBackend, &out.DefaultBackend
		*out = new(netv1.IngressBackend)
		(*in).DeepCopyInto(*out)
	}
	if in.TLS != nil {
		in, out := &in.TLS, &out.TLS
		*out = make([]netv1.IngressTLS, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
	if in.Rules != nil {
		in, out := &in.Rules, &out.Rules
		*out = make([]IngressRule, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopyInto copying the receiver, writing into out. in must be non-nil.
func (in *IngressRule) DeepCopyInto(out *IngressRule) {
	*out = *in
	in.IngressRuleValue.DeepCopyInto(&out.IngressRuleValue)
}

// DeepCopyInto copying the receiver, writing into out. in must be non-nil.
func (in *IngressRuleValue) DeepCopyInto(out *IngressRuleValue) {
	*out = *in
	if in.HTTP != nil {
		in, out := &in.HTTP, &out.HTTP
		*out = new(netv1.HTTPIngressRuleValue)
		(*in).DeepCopyInto(*out)
	}
}

// FromV1IngressSpec transforms from networking.k8s.io/v1 IngressSpec to custom k8gb ingress Spec
func FromV1IngressSpec(v1Spec netv1.IngressSpec) IngressSpec {
	spec := IngressSpec{}
	spec.DefaultBackend = v1Spec.DefaultBackend
	spec.IngressClassName = v1Spec.IngressClassName
	spec.TLS = v1Spec.TLS
	for _, v := range v1Spec.Rules {
		rule := IngressRule{}
		rule.Host = v.Host
		rule.HTTP = v.HTTP
		rule.IngressRuleValue = IngressRuleValue{
			HTTP: v.IngressRuleValue.HTTP,
		}
		spec.Rules = append(spec.Rules, rule)
	}
	return spec
}

// ToV1IngressSpec transforms from k8gb ingress Spec to networking.k8s.io/v1 IngressSpec
func ToV1IngressSpec(spec IngressSpec) netv1.IngressSpec {
	v1Spec := netv1.IngressSpec{}
	v1Spec.DefaultBackend = spec.DefaultBackend
	v1Spec.IngressClassName = spec.IngressClassName
	v1Spec.TLS = spec.TLS
	for _, v := range spec.Rules {
		rule := netv1.IngressRule{}
		rule.Host = v.Host
		rule.HTTP = v.HTTP
		rule.IngressRuleValue = netv1.IngressRuleValue{
			HTTP: v.IngressRuleValue.HTTP,
		}
		v1Spec.Rules = append(v1Spec.Rules, rule)
	}
	return v1Spec
}
